/*
Copyright © 2024 wjsmc
*/
package internal

import (
	"fmt"
	"path/filepath"
	"strconv"

	"github.com/AlecAivazis/survey/v2"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"nodemessage.com/ruov-cli/rlog"
	"nodemessage.com/ruov-cli/types"
	"nodemessage.com/ruov-cli/utils"
)

// ruovTplUrl 下载地址
var ruovTplUrl = "https://file.nodemessage.com/ruov.zip"

// initCmd represents the init command
var initCmd = &cobra.Command{
	Use:   "init",
	Short: "初始化项目",
	Long:  color.New(color.FgYellow).Sprintf(`在当前目录初始化rouv项目,将自动创建数据库`),
	Run: func(cmd *cobra.Command, args []string) {
		// 配置文件处理
		ruovConf, isNew, err := readyConfig()
		if err != nil {
			rlog.Logger.Fatal("项目初始化失败:%v", err)
		}
		if ruovConf == nil {
			rlog.Logger.Fatal("项目初始化失败:配置为空")
			return
		}
		if isNew {
			// 下载模板并解压到app目录
			downTpl(ruovConf)
			// 初始化meta文件
			initMetaInfo(ruovConf)
		} else {
			rlog.Logger.Fatal("项目%s已存在!", ruovConf.AppName)
		}
		// 替换模板数据
		settingPom(ruovConf)
	},
}

func initMetaInfo(ruovConf *types.Config) {
	err := utils.FileCreateDirectories([]string{filepath.Join(ruovConf.AppName, RuovConfPath)})
	if err != nil {
		rlog.Logger.Fatal("项目%s初始化失败:%s目录无法生成:%v", ruovConf.AppName, err)
	}
	err = utils.XmlFileWriteXMLConfig(filepath.Join(ruovConf.AppName, RuovXmlFullPath), ruovConf, nil)
	if err != nil {
		rlog.Logger.Fatal("项目%s初始化失败:meta文件无法生成:%v", ruovConf.AppName, err)
	}
	rlog.Logger.Info("项目%s meta文件生成成功!", ruovConf.AppName)
}

// readyConfig 准备初始环境
func readyConfig() (config *types.Config, isNew bool, err error) {
	if utils.FilePathExists(RuovXmlFullPath) {
		config, err = utils.XmlFileReadXMLConfig[types.Config](RuovXmlFullPath)
		return
	}
	isNew = true
	rlog.Logger.Info("项目初始化中...")
	config, err = configWizard()
	return
}

func configWizard() (*types.Config, error) {
	config := &types.Config{}

	questions := []*survey.Question{
		{
			Name: "appName",
			Prompt: &survey.Input{
				Message: "应用名称:",
				Default: "ruov",
				Suggest: func(toComplete string) []string {
					return []string{"ruov", "app", "web"}
				},
				Help: "要符合目录名规范",
			},
			Validate: survey.ComposeValidators(survey.Required, func(val interface{}) error {
				isOk, errMsg := utils.FileIsValidDirectoryName(val.(string))
				if isOk {
					if utils.FilePathExists(val.(string)) {
						return fmt.Errorf("目录已存在")
					}
					return nil
				} else {
					return fmt.Errorf(errMsg)
				}
			}),
		},
		{
			Name: "dbHost",
			Prompt: &survey.Input{
				Message: "数据库主机:",
				Default: "localhost",
			},
			Validate: survey.ComposeValidators(survey.Required),
		},
		{
			Name: "dbPort",
			Prompt: &survey.Input{
				Message: "数据库端口:",
				Default: "3306",
			},
			Validate: survey.ComposeValidators(survey.Required, func(val interface{}) error {
				_, err := strconv.Atoi(val.(string))
				if err != nil {
					return fmt.Errorf("请输入有效的整数")
				}
				return nil
			}),
		},
		{
			Name: "dbUsername",
			Prompt: &survey.Input{
				Message: "数据库用户名:",
				Default: "root",
			},
			Validate: survey.ComposeValidators(survey.Required),
		},
		{
			Name: "dbPassword",
			Prompt: &survey.Password{
				Message: "数据库密码:",
			},
			Validate: survey.ComposeValidators(survey.Required),
		},
		{
			Name: "dbName",
			Prompt: &survey.Input{
				Message: "数据库名:",
			},
			Validate: survey.ComposeValidators(survey.Required),
		},
	}

	answers := struct {
		AppName    string
		DBHost     string
		DBPort     string
		DBUsername string
		DBPassword string
		DBName     string
	}{}

	err := survey.Ask(questions, &answers)
	if err != nil {
		return nil, err
	}

	config.BasePack = "com.ruov"
	config.AppName = answers.AppName
	config.Database.Host = answers.DBHost
	config.Database.Port, _ = strconv.Atoi(answers.DBPort)
	config.Database.Username = answers.DBUsername
	config.Database.Password = answers.DBPassword
	config.Database.DBName = answers.DBName
	dns, err := utils.DbPing(config.Database.Username, config.Database.Password, config.Database.Host, config.Database.Port, config.Database.DBName)
	if err != nil {
		rlog.Logger.Fatal("数据库 %s 连接失败:%v", dns, err)
	}
	return config, nil
}

func downTpl(ruovConf *types.Config) {
	rlog.Logger.Info("项目%s模板下载中...", ruovConf.AppName)
	err := utils.FileDownloadAndUnzip(ruovTplUrl, ruovConf.AppName)
	if err != nil {
		rlog.Logger.Fatal("项目%s初始化失败:%v", ruovConf.AppName, err)
	}
	appAbs, err := filepath.Abs(ruovConf.AppName)
	if err != nil {
		appAbs = ruovConf.AppName
	}
	rlog.Logger.Info("项目%s模板解压成功!,路径:%s", ruovConf.AppName, appAbs)
}

func settingPom(ruovConf *types.Config) {
	pomPath := filepath.Join(ruovConf.AppName, RuovApiPath, "pom.xml")
	config, err := utils.XmlFileReadXMLConfig[types.TplProjectPom](pomPath)
	if err != nil {
		rlog.Logger.Fatal("项目%s读取pom失败:%v", ruovConf.AppName, err)
	}
	config.Name = ruovConf.AppName
	config.URL = "https://gitee.com/wangjusanmu/ruov"
	config.Description = "ruov-cli 脚手架"
	profileDev := &config.Profiles.Profile[0]
	profileDev.Properties.DatabaseURL = fmt.Sprintf(
		"jdbc:mysql://%s:%d/%s?useUnicode=true&amp;characterEncoding=utf8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=true&amp;serverTimezone=%s",
		ruovConf.Database.Host,
		ruovConf.Database.Port,
		ruovConf.Database.DBName,
		"GMT%2B8")
	profileDev.Properties.DatabaseUsername = ruovConf.Database.Username
	profileDev.Properties.DatabasePassword = ruovConf.Database.Password
	err = utils.XmlFileWriteXMLConfig(pomPath, config, PomHeader)
	if err != nil {
		rlog.Logger.Fatal("项目%s写入pom失败:%v", ruovConf.AppName, err)
	}
}
